<?php

namespace App\Http\Controllers;

use App\Exceptions\BusinessException;
use App\Http\Resources\CompletionResource;
use App\Models\AiApp;
use App\Models\AiLog;
use App\Services\AiService;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Ninex\Lib\Http\Controllers\LibController;
use Slowlyo\OwlAdmin\Models\AdminSetting;

class AiController extends LibController
{
    public $service;
    public function __construct(Request $request,AiService $service)
    {
        parent::__construct($request);
        $this->service = $service;
    }

    public function index()
    {
        $data = $this->service->paginate();
        return $this->success(CompletionResource::collection($data));
    }

    public function completion()
    {
        $settings = AdminSetting::whereIn('key',[
            'app_key',
            'plus_app_id',
            'max_app_id',
        ])->pluck('values','key')->toArray();
        $params = $this->request->all();
        if(!$prompt = Arr::get($params,'input.prompt'))
        {
            return $this->error('请输入prompt');
        }
        $app = auth()->guard('aiapp')->user();
        $imageList = Arr::get($params,'input.images',[]);
        $save = [
            'app_id' => $app->id,
            'prompt' => $prompt,
            'images' => json_encode($imageList),
            'stream' => Arr::get($params,'stream') ? 1: 0,
            'image_response' => json_encode([]),
            'text_response' => json_encode([]),
            'response_text' => '',
        ];

        $appkey = $settings['app_key'];
        if(Arr::get($params,'model') == 'max'){
            $model = 'max';
        }else{
            $model = 'plus';
        }
        $appid = $settings["{$model}_app_id"];
        $save['model'] = $model;
        $save['params'] = json_encode($params);
        $logModel = AiLog::create($save);
        //图片处理
        if($imageList){
            if(empty($app->image_model) || $app->image_token<0){
                throw new BusinessException('图片模型无法使用');
            }
            $response = $this->sendChatCompletionRequest($appkey,$imageList,$app->image_prompt,$app->image_model);
            $text = Arr::get($response,'choices.0.message.content');
            $total_tokens = Arr::get($response,'usage.total_tokens');
            $this->selfcrement($app,'image',$total_tokens);
            $prompt = str_replace(
                ['{prompt}','{text}'],
                [$prompt,$text],
                $app->prompt_tpl
            );
            $logModel->image_response = json_encode($response);
            $logModel->image_token = $total_tokens;
            $logModel->image_request_id = $response['id'];
            $logModel->save();
        }
        $session_id = Arr::get($params,'input.session_id');
        //文字
        if($save['stream'])
        {
            return $this->getStreamResponse($logModel,$app,$appkey,$appid,$prompt,$model,$session_id);//流式返回
        }else{
            return $this->sendDashscopeRequest($logModel,$app,$appkey,$appid,$prompt,$model,$session_id);
        }
    }

    public function selfcrement(AiApp $app,$type,$num)
    {
        if($num <=0 ){
            return '';
        }
        $app->decrement("{$type}_token",$num);
        $app->increment("used_{$type}_token",$num);
    }
    public function sendDashscopeRequest($logModel,$app, $apiKey, $appid, $prompt,$model,$session_id = '') {
        $headers = [
            "Authorization: Bearer $apiKey",
            "Content-Type: application/json"
        ];
        $url = 'https://dashscope.aliyuncs.com/api/v1/apps/' . $appid . '/completion';
        $data = [
            "input" => [
                "prompt" => $prompt,
            ],
            "stream" => false,
        ];
        if (!empty($session_id)) {
            $data['input']['session_id'] = $session_id;
        }
        $ch = curl_init();
        // 设置cURL选项
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

        // 执行cURL请求
        $response = curl_exec($ch);

        // 检查是否有错误发生
        if (curl_errno($ch)) {
            throw new BusinessException('Error:' . curl_error($ch));
        }
        // 关闭cURL会话
        curl_close($ch);
        // 返回响应
        $data = json_decode($response, true);
        $modelData = Arr::get($data,'usage.models.0');
        unset($modelData['model_id']);
        $tokens = array_sum($modelData);
        $this->selfcrement($app,$model,$tokens);
        $this->saveTextLog($logModel,$data,$tokens);
        $data = json_decode($response,1);
        unset($data['usage']);
        return json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    }
    public function getStreamResponse($logModel,$app, $apiKey, $appid, $prompt, $model,$session_id = '')
    {
        // 设置SSE头部
        header("X-Accel-Buffering: no");
        header('Content-Type: text/event-stream');
        header('Cache-Control: no-cache');
        header('Connection: keep-alive');
        header('Access-Control-Allow-Origin: *');

        $url = 'https://dashscope.aliyuncs.com/api/v1/apps/' . $appid . '/completion';
        $data = [
            "input" => [
                "prompt" => $prompt,
            ],
            "parameters" => [
                'incremental_output' => true,
            ],
            "stream" => true,
        ];
        if (!empty($session_id)) {
            $data['input']['session_id'] = $session_id;
        }

        // 初始化cURL会话
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Authorization: Bearer ' . $apiKey,
            'Content-Type: application/json',
            'X-DashScope-SSE: enable'
        ));
        $input_tokens = 0;
        $output_tokens = 0;
        // 设置写入回调函数
        curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, $chunk) use($app,&$logModel,$model,&$input_tokens,&$output_tokens) {
            // 匹配SSE数据格式
            echo $chunk;
            preg_match('/^data:(.*)$/m', $chunk, $matches);
            if (!empty($matches[1])) {
                $data = json_decode($matches[1],1);
                $input_tokens = Arr::get($data,'usage.models.0.input_tokens');
                $output_tokens = Arr::get($data,'usage.models.0.output_tokens');
                $logModel = $this->saveTextLog($logModel,$data,0);
            }
            ob_flush();
            flush();
            return strlen($chunk);
        });
        $total_tokens = $input_tokens+$output_tokens;
        $this->selfcrement($app,$model,$total_tokens);
        $logModel->increment('text_token',$total_tokens);
        // 执行cURL请求
        curl_exec($ch);
        // 关闭cURL会话
        curl_close($ch);
        return '';
    }

    public function saveTextLog($logModel,$data,$token)
    {
        $text_response = json_decode($logModel->text_response);
        $text_response[] = $data;
        $logModel->text_response = json_encode($text_response);
        if(empty($logModel->text_request_id)){
            $logModel->text_request_id = Arr::get($data,'request_id');
        }
        if(empty($logModel->response_text)){
            $logModel->response_text = '';
        }
        $logModel->response_text .= Arr::get($data,'output.text');
        $logModel->save();
        if($token){
            $logModel->increment('text_token',$token);
        }
        return $logModel;
    }
    public function sendChatCompletionRequest($apikey,$urls,$text,$model)
    {
        $content = [];
        try {

            foreach ($urls as $url){
                if(empty($url['url'])){
                    continue;
                }
                $content[] = [
                    'type' => 'image_url',
                    'image_url' => [
                        'url' => 'data:'.$url['mime'].';base64,'.base64_encode(file_get_contents($url['url']))
                    ]
                ];
            }
        }catch (\Throwable $e){
            throw new BusinessException('获取图片失败');
        }
        $content[] = [
            'type' => 'text',
            'text' => $text
        ];
        $data = [
            'model' => $model,
            'messages' => [
                [
                    'role' => 'user',
                    'content' => $content
                ]
            ]
        ];
        $json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions',
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 99999,
            CURLOPT_CONNECTTIMEOUT => 99999,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => 'POST',
            CURLOPT_POSTFIELDS => $json,
            CURLOPT_HTTPHEADER => array(
                'Authorization: Bearer '.$apikey,
                'Content-Type: application/json',
                'Content-Length: '.strlen($json)
            ),
        ));

        $response = curl_exec($curl);

        curl_close($curl);
        $data = json_decode($response,true);
        return $data;//$data['choices'][0]['message']['content'] ?? '';

    }


}
